import {EmbedCache, LinkCache, TFile} from "obsidian";
import {Common} from "./common";
import * as path from "path";

export interface LinkSectionInfo {
	hasSection: boolean
	link: string
	section: string
}

export function splitLinkToPathAndSection(link: string): LinkSectionInfo {
	let res: LinkSectionInfo = {
		hasSection: false,
		link: link,
		section: ""
	}

	if (!link.contains('#'))
		return res;

	//@ts-ignore
	let linkBeforeHash = link.match(/(.*?)#(.*?)$/)[1];
	//@ts-ignore
	let section = link.match(/(.*?)#(.*?)$/)[2];

	// JimmyMo to compatiable to image hash like xxx.png#inline|300
	let isMarkdownSection = section != ""; // && linkBeforeHash.endsWith(".md"); // for links with sections like [](note.md#section)
	let isPdfPageSection = section.startsWith("page=") && linkBeforeHash.endsWith(".pdf"); // for links with sections like [](note.pdf#page=42)

	if (isMarkdownSection || isPdfPageSection) {
		res = {
			hasSection: true,
			link: linkBeforeHash,
			section: section
		}
	}

	return res;
}

export function getFileByLink(link: string, owningNotePath: string, allowInvalidLink: boolean = true): TFile | undefined {
	if (link.trim() === ""){ // JimmyMo process link with only hash e.g. [[#^i0xwp8]]
		return undefined;
	}
	link = splitLinkToPathAndSection(link).link;
	if (allowInvalidLink) {
		return this.app.metadataCache.getFirstLinkpathDest(link, owningNotePath);
	}
	let fullPath = getFullPathForLink(link, owningNotePath);
	return getFileByPath(fullPath);
}
function getFullPathForLink(link: string, owningNotePath: string): string {
	link = splitLinkToPathAndSection(link).link;
	link = Common.normalizePathForFile(link);
	owningNotePath = Common.normalizePathForFile(owningNotePath);

	let parentFolder = owningNotePath.substring(0, owningNotePath.lastIndexOf("/"));
	let fullPath = path.join(parentFolder, link);

	fullPath = Common.normalizePathForFile(fullPath);
	return fullPath;
}
function getFileByPath(path: string): TFile {
	path = Common.normalizePathForFile(path);
	return this.app.vault.getAbstractFileByPath(path) as TFile;
}

export function getAllCachedLinksToFile(filePath: string): { [notePath: string]: LinkCache[]; } {
	let allLinks: { [notePath: string]: LinkCache[]; } = {};
	let notes = this.app.vault.getMarkdownFiles();

	if (notes) {
		for (let note of notes) {
			if (note.path == filePath)
				continue;

			//!!! this can return undefined if note was just updated
			let links = this.app.metadataCache.getCache(note.path)?.links;

			if (links) {
				for (let link of links) {
					// let linkFullPath = getFullPathForLink(link.link, note.path);
					let linkFile = getFileByLink(link.link, note.path);
					if (linkFile) {
						// console.log(linkFile.path)
						if (linkFile.path === filePath) {
							if (!allLinks[note.path])
								allLinks[note.path] = [];
							allLinks[note.path].push(link);
						}
					}
				}
			}
		}
	}

	return allLinks;
}


export function getAllCachedEmbedsToFile(filePath: string): { [notePath: string]: EmbedCache[]; } {
	let allEmbeds: { [notePath: string]: EmbedCache[]; } = {};
	let notes = this.app.vault.getMarkdownFiles();

	if (notes) {
		for (let note of notes) {
			if (note.path == filePath)
				continue;

			//!!! this can return undefined if note was just updated
			let embeds = this.app.metadataCache.getCache(note.path)?.embeds;

			if (embeds) {
				for (let embed of embeds) {
					let linkFile = getFileByLink(embed.link, note.path);
					if (linkFile) {
						// console.log(linkFile.path)
						if (linkFile.path === filePath) {
							if (!allEmbeds[note.path])
								allEmbeds[note.path] = [];
							allEmbeds[note.path].push(embed);
						}
					}
				}
			}
		}
	}

	return allEmbeds;
}

// JM: 这个方法对每个embed或link去判断他是不是一个在vault中合法的markdown笔记
export function isValidMarkdownNoteInVault(linkCache: LinkCache, markdown: TFile): boolean {
	// const extensionList = ["5", "xyz"]
	const linkFileName = splitLinkToPathAndSection(linkCache.link).link.split("/").slice(-1)[0];
	// const linkFileName = link.link.split("/").slice(-1)[0];
	// 这里linkFileName如果不以.md结尾，则可能是一个附件或者是markdown
	if (linkFileName.endsWith(".excalidraw")) { // TODO: 将这个配置化，作为忽略的md文件，不认为其是md。
		return false; // 这里将.excalidraw.md作为需要移动的附件，因此直接返回false;
	}
	else if (linkFileName.endsWith(".md")){ // 一般不会进来，如果有.md扩展名，那么直接和markdown的完整名比较（完整名即包含.md后缀） // 如果被移动的是.md，那么这个md如果在vault中存在，那就不被过滤 // 不被过滤意味着需要移动
		// 如果link所指文件是一个存在于vault中的合法markdown笔记，则返回true，否则返回false
		return linkFileName.trim().toLowerCase() === markdown.name.trim().toLowerCase();
	}
	else if (linkFileName.indexOf(".") != -1){ // linkFileName本身含有. e.g. 测试.net framework3.5 // 如果不是.md扩展名，但是仍然包含.
		// 如果是.png会放进来，但是.png.md就不会匹配又排除掉，但如果是“测试.net framework3.5”则变成“测试.net framework3.5.md”是可以匹配的
		return (linkFileName + ".md").trim().toLowerCase() === markdown.name.trim().toLowerCase();
	}
	else if (linkFileName.indexOf(".") == -1) { // 标准笔记入口，没有扩展名的情况一般.md结尾的笔记都省略了扩展名 // 如果不包含，那么仅需要用其和markdown的basename比较，全不匹配的就是附件了
		// 如果没有.md扩展名，那么和markdown的basename比较
		return linkFileName.trim().toLowerCase() === markdown.basename.trim().toLowerCase();
	}
	else { // .png这种附件入口，不以.md结尾，但又含有.的文件，都不认为是vault内的markdown
		// 有个bug就是markdown basename本身含有. e.g. 测试.net framework3.5，这种应该放入上一档
		return false;
	}
}
